package httpserver

import (
	"context"
	"gitee.com/scottq/go-framework/src/v1/log"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"strings"
)

type HttpServer struct {
	name      string
	listenAdd string
	routers   []*Router
	rHandler  *httprouter.Router
	server    *http.Server

	config *ServerConfig

	log.InvokeLog
}

func NewHttpServer(name string, addr string, ops ...ServerOps) (*HttpServer, error) {
	server := &HttpServer{
		name:      name,
		listenAdd: addr,
		routers:   []*Router{},
		config:    defaultServerConfig,
		rHandler:  httprouter.New(),
	}

	for i, _ := range ops {
		ops[i](server)
	}

	//register health router
	server.defaultRoute()

	return server, nil
}

func (s *HttpServer) Router() *httprouter.Router {
	return s.rHandler
}

func (s *HttpServer) RouteFiles(path string, f http.FileSystem) *HttpServer {
	s.rHandler.ServeFiles(path+"/*filepath", f)
	return s
}

func (s *HttpServer) RouteHandler(method, path string, f http.Handler, middleware []Middleware) *HttpServer {
	s.addRouteHandler(method, path, f, middleware)
	return s
}

func (s *HttpServer) RouteAll(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer {
	s.addRoute(http.MethodPost, path, f, middleware)
	s.addRoute(http.MethodGet, path, f, middleware)
	s.addRoute(http.MethodOptions, path, f, middleware)
	s.addRoute(http.MethodDelete, path, f, middleware)
	s.addRoute(http.MethodPut, path, f, middleware)
	return s
}

func (s *HttpServer) RoutePost(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer {
	s.addRoute(http.MethodPost, path, f, middleware)
	return s
}
func (s *HttpServer) RouteGet(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer {
	s.addRoute(http.MethodGet, path, f, middleware)
	return s
}
func (s *HttpServer) RouteOptions(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer {
	s.addRoute(http.MethodOptions, path, f, middleware)
	return s
}
func (s *HttpServer) RouteDelete(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer {
	s.addRoute(http.MethodDelete, path, f, middleware)
	return s
}
func (s *HttpServer) RoutePut(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer {
	s.addRoute(http.MethodPut, path, f, middleware)
	return s
}

//默认的路由处理
func (s *HttpServer) defaultRoute() *HttpServer {
	//健康检查
	if s.config.healthCheck {
		path := s.config.healthPath
		s.addRoute(http.MethodGet, path, HealthF, nil)
		s.addRoute(http.MethodPost, path, HealthF, nil)
	}

	//options操作
	if s.config.acceptOptions {
		s.addRoute(http.MethodOptions, "/", EmptyHandle, nil)
	}

	return s
}

func (s *HttpServer) addRoute(method, path string, f HttpRouteFunc, middleware []Middleware) *HttpServer {
	s.routers = append(s.routers, &Router{
		Path:         path,
		Method:       strings.ToUpper(method),
		RouteHandler: f,
		Middleware:   middleware,
	})
	return s
}

func (s *HttpServer) addRouteHandler(method, path string, f http.Handler, middleware []Middleware) *HttpServer {
	s.routers = append(s.routers, &Router{
		Path:        path,
		Method:      strings.ToUpper(method),
		HttpHandler: f,
		Middleware:  middleware,
	})
	return s
}

func (s *HttpServer) initRouter() error {
	routers := map[string]*Router{}
	for _, x := range s.routers {
		routers[x.hash()] = x
	}

	for _, x := range routers {
		x.invokeRegister(s.rHandler, s.config)
	}
	return nil
}

func (s *HttpServer) Name() string {
	return s.name
}

func (s *HttpServer) Run() error {

	err := s.initRouter()
	if err != nil {
		return err
	}
	s.Info("[%s]http running at %s", s.name, s.listenAdd)

	srv := &http.Server{
		Addr:    s.listenAdd,
		Handler: s.rHandler,
	}
	s.server = srv

	return srv.ListenAndServe()
}

func (s *HttpServer) Stop() error {
	if s.server == nil {
		return nil
	}
	s.Info("http stop %s", s.listenAdd)

	err := s.server.Shutdown(context.Background())
	s.server = nil
	return err
}
